<!DOCTYPE html>
<html lang="zh_CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>addEventListener（事件流注册分析）</title>
    <style>
      .outer,
      .middle,
      .inner1,
      .inner2 {
        display: block;
        width: 520px;
        padding: 15px;
        margin: 15px;
        text-decoration: none;
      }
      .outer {
        border: 1px solid red;
        color: red;
      }
      .middle {
        border: 1px solid green;
        color: green;
        width: 460px;
      }
      .inner1,
      .inner2 {
        border: 1px solid purple;
        color: purple;
        width: 400px;
      }
    </style>
  </head>
  <body>
    <div class="outer">
      outer, once & none-once
      <div class="middle" target="_blank">
        middle, capture & none-capture
        <a class="inner1" href="https://www.mozilla.org" target="_blank">
          inner1, passive & preventDefault(which is not allowed)
        </a>
        <a class="inner2" href="https://developer.mozilla.org/" target="_blank">
          inner2, none-passive & preventDefault(not open new page)
        </a>
      </div>
    </div>
    <script>
      let outer = document.getElementsByClassName('outer')[0]
      let middle = document.getElementsByClassName('middle')[0]
      let inner1 = document.getElementsByClassName('inner1')[0]
      let inner2 = document.getElementsByClassName('inner2')[0]

      let capture = { capture: true }
      let noneCapture = { capture: false }
      let once = { once: true }
      let noneOnce = { once: false }
      let passive = { passive: true }
      let nonePassive = { passive: false }
      /**
       * 时间监听执行顺序，先进先出（先注册的会先执行）
       **/

      /**
       * 表示 listener 在添加之后最多只调用一次。如果是 true， listener 会在其被调用之后自动移除
       **/
      outer.addEventListener('click', onceHandler, once)
      outer.addEventListener('click', noneOnceHandler, noneOnce)
      /**
       * 表示 listener 会在该类型的事件捕获阶段传播到该 EventTarget 时触发
       * 白话：capture为true时：子集使用stopPropagation阻止冒泡时【也会执行】
       **/
      middle.addEventListener('click', captureHandler, capture)
      middle.addEventListener('click', noneCaptureHandler, noneCapture)
      /**
       * 设置为true时，表示 listener 永远不会调用 preventDefault【元素默认行为】。
       * 如果 listener 仍然调用了这个函数，客户端将会忽略它并抛出一个控制台警告。
       * 查看 使用 passive 改善的滚屏性能 了解更多
       **/
      inner1.addEventListener('click', passiveHandler, passive)
      inner2.addEventListener('click', nonePassiveHandler, nonePassive)

      function onceHandler(event) {
        alert('outer, once, 1')
      }
      function noneOnceHandler(event) {
        alert('outer, none-once, default, 2')
      }
      function captureHandler(event) {
        /**
         * 如果有多个相同类型事件的事件监听函数绑定到同一个元素，
         * 当该类型的事件触发时，它们会按照被添加的顺序执行。
         * 如果其中某个监听函数执行了 event.stopImmediatePropagation() 方法，
         * 则当前元素剩下的监听函数将不会被执行。
         * （译者注：注意与 event.stopPropagation() 之间的区别）
         **/
        //event.stopImmediatePropagation()
        alert('middle, capture, 3')
      }
      function noneCaptureHandler(event) {
        //event.stopImmediatePropagation()
        alert('middle, none-capture, default, 4')
      }

      function passiveHandler(event) {
        //preventDefault: 在调用passive事件监听器内部不能使用preventDefault
        //event.preventDefault()
        alert('inner1, passive, open new page, 5')
      }
      function nonePassiveHandler(event) {
        /**
         * 在事件流的任何阶段调用preventDefault()都会取消事件，这意味着任何通常被该实现触发并作为结果的默认行为都不会发生。
         * 你可以使用 Event.cancelable 来检查该事件是否支持取消。为一个不支持cancelable的事件调用preventDefault()将没有效果。
         **/
        event.preventDefault()
        //stopPropagation: 阻止捕获和冒泡阶段中当前事件的进一步传播
        event.stopPropagation()
        alert('inner2, none-passive, default, not open new page, 6')
      }
    </script>
  </body>
</html>
